home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 43 / Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso / -serious- / programming / other / renderlib / doc / tutorial < prev    next >
Text File  |  1999-06-14  |  19KB  |  535 lines

  1.  
  2. tutorial
  3. -----------------------------
  4.  
  5.   this tutorial intends to generally explain basic terms of image
  6.   processing and to instruct the programming of render.library.
  7.  
  8.  
  9.  
  10. introduction
  11. -----------------------------
  12.  
  13.   render.library provides low-level image processing. there are no
  14.   functions implemented that interact with higher-level resources,
  15.   such as rastports or datatypes. you may call render.library an
  16.   image processing kernel.
  17.  
  18.   there's no reason for hesitation, though. i hope this tutorial
  19.   will help you to find the thread to image processing and
  20.   conversion. as you will see, the functions provided with
  21.   render.library are very easy to use, once you've understood the
  22.   basic terms, and most functions provide much more power and
  23.   functionality than it might appear at first sight.
  24.  
  25.  
  26.  
  27. philosophy
  28. -----------------------------
  29.  
  30.   function interfaces are kept lean and logical. first of all i
  31.   focused on using as few definitions as possible. you will notice
  32.   that you can use the majority of render.library's functions
  33.   without setting up a single structure. each function was reduced
  34.   to an absolute minimum of mandatory parameters. any argument that
  35.   in some way could be assigned a default value to has been made
  36.   optional and was banned to the taglists.
  37.  
  38.   render.library is layouted quasi object-oriented. everything is
  39.   kept in black boxes, and objects heavily interact internally, only
  40.   you don't know anything about the chemistry. many functions may be
  41.   interpreted as constructors, destructors and methods, only the
  42.   interfaces are implemented procedurally. there is nothing
  43.   available for misguiding, insane assumptions.
  44.  
  45.  
  46. overview
  47. -----------------------------
  48.  
  49.   render.library covers the following domains:
  50.  
  51.     > planar to chunky conversion
  52.  
  53.       and vice versa. the functions in this domain are considered
  54.       low-level, and they do not interact with higher-level
  55.       graphics.library instances such as rastports. you have to
  56.       take good care not to play havoc with non-standard bitmaps.
  57.       please read the appropriate autodoc chapters very carefully.
  58.  
  59.       - Planar2ChunkyA()
  60.       - Chunky2BitMapA()
  61.  
  62.  
  63.     > chunky to truecolor conversion
  64.  
  65.       this is a simple task, and render.library serves it with
  66.       high speed and flexibility. Amiga-specific modes (HAM6 and
  67.       HAM8) are correctly handled even with horizontal offsets.
  68.         
  69.       - Chunky2RGBA()
  70.  
  71.  
  72.     > palettes
  73.     
  74.       render.library uses a special type of color-lookup tables,
  75.       called 'palettes'. a render.library palette is much more
  76.       than a mere table of RGB values. all that nasty stuff is
  77.       hidden from you throughout these functions:
  78.  
  79.       - CreatePaletteA()
  80.       - ImportPaletteA()
  81.       - ExportPaletteA()
  82.       - SortPaletteA()
  83.  
  84.  
  85.     > histograms
  86.     
  87.       histograms are in most cases not more than a means to an
  88.       end. they are required for color reduction, statistics, and
  89.       for certain low-level functions. render.library supports
  90.       'real' truecolor histograms with up to 24bit resolution.
  91.  
  92.       - CreateHistogramA()
  93.       - AddChunkyImageA()
  94.       - AddRGBImageA()
  95.       - AddRGB()
  96.       - AddHistogram()
  97.       - CountRGB()
  98.       - QueryHistogram()
  99.  
  100.  
  101.     > color reduction (quantization)
  102.     
  103.       this task is everything but trivial. render.library
  104.       uses a sophisticated algorithm that can stand the test
  105.       with the most-elaborated implementations on the Amiga
  106.       platform.
  107.  
  108.       - ExtractPaletteA()
  109.  
  110.  
  111.     > truecolor to chunky conversion (rendering)
  112.  
  113.       this task was the initial idea for render.library, and
  114.       render.library deserves its name. just have a look at all
  115.       those possible taglist arguments for
  116.       
  117.       - RenderA()
  118.  
  119.  
  120.     > chunky to chunky conversion
  121.         
  122.       this is similar to RenderA(), only that it accepts
  123.       chunky bytes as input.
  124.         
  125.       - ConvertChunkyA()
  126.       - CreatePenTableA()
  127.  
  128.  
  129.     > mapping
  130.     
  131.       in addition to those fully-featured rendering and
  132.       chunky-conversion functions, render.library offers a
  133.       low-level conversion class called mapping-engine.
  134.       
  135.       - CreateMapEngineA()
  136.       - MapChunkyArrayA()
  137.       - MapRGBArrayA()
  138.     
  139.  
  140.     > scaling
  141.     
  142.       render.library provides an own scaling class. its instances
  143.       are called scaling-engines. the performance of
  144.       non-interpolating scaling-engines comes close to CopyMem().
  145.       Scaling-engines may be passed to RenderA() and
  146.       ConvertChunkyA(), allowing scaling and rendering in a
  147.       single pass.
  148.  
  149.       - CreateScaleEngineA()
  150.       - ScaleA()
  151.       - ScaleOrdinate()
  152.  
  153.  
  154.     > alpha-channel
  155.  
  156.       this is a trivial task with render.library and can be
  157.       achieved with these functions:
  158.         
  159.       - InsertAlphaChannelA()
  160.       - ExtractAlphaChannelA()
  161.       - ApplyAlphaChannelA()
  162.       - MixRGBArrayA()
  163.  
  164.  
  165.     > memory management
  166.  
  167.       render.library features a lean and simple, but yet
  168.       effective memory management system throughout these
  169.       functions:
  170.         
  171.       - CreateRMHandlerA()
  172.       - AllocRenderMem()
  173.       - AllocRenderVec()
  174.  
  175.  
  176.  
  177. data types
  178. -----------------------------
  179.  
  180.   what kind of data can be processed with render.library?
  181.   currently, there are the following formats available:
  182.  
  183.     > PIXFMT_0RGB_32          (ULONG)
  184.  
  185.       longword truecolor pixels, with the sequence
  186.         
  187.       0x00rrggbb
  188.         
  189.       the upmost byte is not defined, and in most cases may
  190.       contain alpha-channel information.
  191.         
  192.     > PIXFMT_CHUNKY_CLUT      (UBYTE)
  193.         
  194.       chunky-byte pixels with color-lookup table. a pixel's
  195.       actual color is not defined throughout this format.
  196.       therefore you need a palette for most operations with
  197.       arrays of chunky bytes. usually, the byte value
  198.       acts directly as an index to the color-lookup table.
  199.  
  200.  
  201.   for certain operations, an additional specification is required
  202.   for the access to a color-lookup table:
  203.  
  204.     > COLORMODE_CLUT
  205.     
  206.       this mode defines 'normal' color lookup (see above). one
  207.       byte directly acts as an index to a color-lookup table.
  208.  
  209.     > COLORMODE_HAM6
  210.  
  211.       this mode defines HAM6 color lookup. one byte does not
  212.       necessarily reference a palette index.
  213.  
  214.     > COLORMODE_HAM6
  215.  
  216.       this mode defines HAM8 color lookup. one byte does not
  217.       necessarily reference a palette index.
  218.  
  219.   remember that COLORMODE_HAM6 and COLORMODE_HAM8 still apply to
  220.   chunky pixels, although HAM is an Amiga specific format that was
  221.   (unfortunately) never defined for chunky bytes, but rather for
  222.   planar data ('bitplanes').
  223.  
  224.  
  225.  
  226. memory management
  227. -----------------------------
  228.  
  229.   since image processing is in general quite hungry for memory
  230.   resources, render.library offers a both simple and effective
  231.   custom memory management.
  232.   
  233.   you don't need to use it, but it may help you to make things
  234.   easier and faster. under normal circumstances, you probably want
  235.   to set up a pooled memory environment. pooled memory helps to
  236.   avoid memory fragmentation, and it preserves the system's public
  237.   memory lists from too much stressing. create a pooled memhandler
  238.   as follows:
  239.  
  240.     memhandler = CreateRMHandler(RND_MemType, RMHTYPE_POOLED,
  241.      TAG_DONE);
  242.  
  243.   * note: pooled memory is not available prior to exec v39. if
  244.   not available, just create a 'standard' memory handler with
  245.   RMHTYPE_PUBLIC - the default value. if your project won't
  246.   include many large images, palettes and histograms, you
  247.   might as well create a 'standard' memory handler.
  248.  
  249.   you might even live without a memhandler, since the memhandler
  250.   argument is always optional - public memory will be used in
  251.   this case. nevertheless, i recommend to use a memhandler. it
  252.   helps you to easily upgrade your code to a more sophisticated
  253.   memory management when necessary. for the use with dynamic
  254.   histograms (see next section), a pooled memory handler is
  255.   highly advised.
  256.  
  257.   you may also set up a memory manager that operates in a static
  258.   block of memory. this is similar to the memory management of
  259.   programs like AdPro. they grab a large block of memory at
  260.   startup and allocate all intermediate buffers from this memory
  261.   area. example:
  262.  
  263.     memhandler = CreateRMHandler(RND_MemType, RMHTYPE_PRIVATE,
  264.         RND_MemBlock, my_memblock,
  265.         RND_MemSize, my_memblock_size, TAG_DONE);
  266.  
  267.   * note: private memory management is less flexible than a
  268.   pooled memory environment. once the static buffer is full or
  269.   becomes fragmented, further allocations will fail. v39 exec
  270.   pools will automatically grow and shrink to the required size.
  271.   
  272.   not only render.library functions may profit from a memhandler.
  273.   your application has access to it throughout these functions:
  274.  
  275.     mem = AllocRenderMem(memhandler, size);
  276.     FreeRenderMem(memhandler, mem, size);
  277.  
  278.     mem = AllocRenderVec(memhandler, size);
  279.     FreeRenderVec(mem);
  280.  
  281.   the main idea is to allow your application and render.library to
  282.   share a particular memory pool. this will keep the whole memory
  283.   management lean and effective.
  284.  
  285.  
  286.  
  287. histograms
  288. -----------------------------
  289.  
  290.   a histogram is an object that holds color information. it
  291.   maintains a counter for each color.
  292.  
  293.   many functions are related to histograms. their creation is
  294.   quite simple:
  295.  
  296.     histogram = CreateHistogram(RND_RMHandler, memhandler,
  297.                     RND_HSType, HSTYPE_15BIT_TURBO,
  298.                     TAG_DONE);
  299.  
  300.   render.library offers two different histogram schemes: the
  301.   _TURBO types are provided with tables, the 'normal' types use
  302.   digital trees. tabular histograms are very fast, but their
  303.   memory consumption is determined according to 2^bits x 4
  304.   bytes. with other words, a 12bit histogram is very small (8192
  305.   bytes), but a 24bit histogram would require 64mb of memory. it
  306.   would be nonsense to create a 24bit tabular histogram anyway,
  307.   since most images do not contain all possible RGB values. that's
  308.   why _TURBO histograms are limited to 12, 15, and 18 bit
  309.   resolution.
  310.  
  311.   tree histograms are more flexible. their memory consumption is
  312.   not predictable, because they are created dynamically. a
  313.   drawback is that every single RGB entry in a tree histogram
  314.   requires 20 bytes of memory. the tree type allows you to create
  315.   'real' histograms with full 24bit accuracy. by the way, this is
  316.   the only way to evaluate the effective number of different
  317.   colors in an image. (most image processing applications operate
  318.   with 15bit histograms and tell you nonsense about the number of
  319.   colors found.)
  320.  
  321.   * a 15 bit _TURBO histogram is the best choice in most cases.
  322.   as mentioned before, most image processing applications use
  323.   this resolution. render.library histograms are interpolated.
  324.   this reasonably compensates the loss of information.
  325.   
  326.   now that we've created a histogram, what are we going to do with
  327.   it? first of all, we have to load it with color information.
  328.  
  329.     success = AddRGBImage(histogram, rgb_array, 
  330.                                 640, 480, NULL);
  331.  
  332.   in this example, a 640×480 truecolor image is added to the
  333.   histogram. you may of course add as many pictures as you like,
  334.   e.g. in order to record all the single frames of an animation.
  335.   it's also possible to directly add chunky images to a histogram:
  336.  
  337.      success = AddChunkyImage(histogram, chunky_array, 640, 480,
  338.             palette, NULL);
  339.  
  340.   (as you can see, chunky images require a palette. palettes will
  341.   be covered by the next chapter.)
  342.  
  343.   * note: the return value <success> is not boolean, it's
  344.   defined with constants. you must check for ADDH_SUCCESS, since
  345.   adding data to histograms may fail at any time. your histogram
  346.   won't be corrupted in that case, but if you don't check the
  347.   return value, you can't depend on finding your histogram in a
  348.   state that correctly represents the data you've added.
  349.   
  350.   you can find out about certain histogram parameters with the
  351.   QueryHistogram() function. for instance
  352.  
  353.     number_of_pixels = QueryHistogram(histogram, RND_NumPixels);
  354.     number_of_colors = QueryHistogram(histogram, RND_NumColors);
  355.  
  356.   another way to access histograms is the CountRGB() function. it
  357.   returns the number of pixels recorded for a specific RGB value:
  358.  
  359.     pixels_represented = CountRGB(histogram, 0x00rrggbb);
  360.  
  361.   * note: according to current definitions, histograms can hold
  362.   the information for 2^32 (4,28 billions) pixels. as long as no
  363.   overflow occurs to a single entry inside the histogram, they
  364.   may even contain 2^32 different colors. further
  365.   histogram-related processing (e.g. quantization) is defined
  366.   for 2^32 pixels, though.
  367.  
  368.  
  369.  
  370. palettes
  371. -----------------------------
  372.  
  373.   most functions dealing with chunky pixels require color-lookup
  374.   tables. in the context of render.library, they are called
  375.   'palettes'. palettes cover many technical details internally.
  376.   a palette is created this way:
  377.  
  378.     palette = CreatePalette(NULL);
  379.  
  380.   this sets up a palette of 15bit resolution. these 15bit suffice
  381.   in most situations, and they are taken into account only if some
  382.   kind of rendering or mapping takes place. more control can be
  383.   obtained via taglist arguments:
  384.  
  385.     palette = CreatePalette(RND_HSType, HSTYPE_12BIT, TAG_DONE);
  386.  
  387.   as you can see, a palette's resolution is specified analogously
  388.   to a histogram's resolution.
  389.   
  390.   * note: palettes do not differenciate between _TURBO and
  391.   non-TURBO types.
  392.   
  393.   in addition to that, you can supply CreatePalette() with a
  394.   memhandler (which is not a bad idea at all):
  395.  
  396.     palette = CreatePalette(RND_RMHandler, memhandler, TAG_DONE);
  397.  
  398.   after all, what you get is just an empty palette ready for being
  399.   loaded with colors. by default, ImportPaletteA() handles
  400.   0x00rrggbb color entries. you may as well import LoadRGB32-alike
  401.   and LoadRGB4-type tables.
  402.  
  403.     ULONG colortable[5] =
  404.         {0xff0088, 0x007532, 0x435278, 0xffffff, 0x000000};
  405.  
  406.     ImportPalette(palette, colortable, 5, NULL);
  407.  
  408.   you may import colors mulitple times and specify
  409.   offsets:
  410.  
  411.     ImportPalette(palette, colortable1, 10, NULL);
  412.     ImportPalette(palette, colortable2, 20, RND_NewPalette, FALSE,
  413.         RND_FirstColor, 10, TAG_DONE);
  414.  
  415.   with RND_NewPalette set to FALSE, ImportPaletteA() merges
  416.   color entries to a palette. the RND_FirstColor tag specifies
  417.   the offset where to add new colors. the total number of
  418.   colors in a palette is automatically maintained and updated.
  419.   the only restriction is that you are neither allowed to
  420.   import more than 256 colors, nor to import beyond the 256th
  421.   entry. the counterpart of ImportPaletteA() is
  422.   ExportPaletteA().
  423.  
  424.   another way to load a palette with colors is via
  425.   ExtractPaletteA() - refer to the next section.
  426.  
  427.  
  428.  
  429. quantization
  430. -----------------------------
  431.  
  432.   i've got you here, right? quantization ('color reduction') is
  433.   extremely easy with render.library. you just have to supply a
  434.   source histogram and a destination palette.
  435.  
  436.     success = ExtractPalette(histogram, palette, numcolors, NULL);
  437.  
  438.   this is the basic function call. it will extract the given
  439.   number of colors from the histogram and insert it into the
  440.   palette. refer to the autodocs for further details.
  441.  
  442.  
  443.  
  444. rendering
  445. -----------------------------
  446.  
  447.   now for the climax of it all and to what gave render.library its
  448.   name. let's transform a RGB array to chunky pixels:
  449.  
  450.     success = Render(rgbarray, width, height, chunkyarray,
  451.                 palette, tags);
  452.  
  453.   there are many tags available, for dithering, offsets, secondary
  454.   conversions, HAM mode support, scaling, callback hooks, and
  455.   more. the same applies to the chunky-byte equivalent:
  456.  
  457.     success = ConvertChunky(sourcearray, sourcepalette,
  458.         width, height, destarray, destpalette, tags);
  459.  
  460.   no need to mention that these functions are quite fast. if
  461.   they're still not fast enough for your purposes, refer to the
  462.   next section.
  463.  
  464.  
  465.  
  466. mapping
  467. -----------------------------
  468.  
  469.   you are disappointed by the speed of Render(), because it is
  470.   only several times faster than any other software on the Amiga?
  471.   then you have to enter the wonderful realm of mapping-engines.
  472.   mapping-engines focus on three aspects: a) speed, b) speed, c)
  473.   speed.
  474.   
  475.   * mapping-engines depend on a destination palette. The
  476.   contents of that destination palette may change, but it must
  477.   not be deleted prior to dependent mapping-engines.
  478.   
  479.   the mapping-engine may additionally depend on a histogram
  480.   containing the color information of those pixels that are
  481.   going to be mapped. this histogram has to be of a _TURBO
  482.   type of the same resolution as the palette. if there's a
  483.   histogram available that fits these specifications, you
  484.   are strongly recommended to use it¹. this improves speed
  485.   remarkably.
  486.  
  487.     mapengine = CreateMapEngine(destpalette, NULL);
  488.  
  489.     mapengine =
  490.         CreateMapEngine(destpalette, RND_Histogram, histogram,
  491.         TAG_DONE);
  492.  
  493.   now there are two ways of using a mapping-engine. the
  494.   preferrable way is to pass it to RenderA() or ConvertChunkyA()
  495.   with the RND_MapEngine tag argument. if you can manage without
  496.   dithering, scaling, callback hooks and alike, you might as well
  497.   use it with these functions:
  498.  
  499.     MapRGBArray(mapengine, rgbarray, width, height, chunkyarray,
  500.     tags);
  501.  
  502.     MapChunkyArray(mapengine, sourcearray, sourcepalette, width,
  503.     height, destarray, tags);
  504.  
  505.   the above functions have got very low overhead and provide
  506.   rather primitive data transfer schemes. MapRGBArrayA() comes
  507.   close to physical bus performance (with totally 4 memory
  508.   accesses per pixel).
  509.   
  510.   * a drawback with MapRGBArrayA() is that your RGB pixels may not
  511.   contain a trailing alphachannel-byte. it must by set to zero,
  512.   otherwise you must use RenderA() instead.
  513.   
  514.   a call to a function with a mapping-engine can be quite slow
  515.   when invoked for the first time (or whenever the destination
  516.   palette changed). the mapping-engine's internal buffers have
  517.   to be (re-)constructed then. that's where the optional
  518.   histogram gets into action: only those RGB values actually
  519.   appearing in the histogram are updated. if no histogram was
  520.   specified with CreateMapEngineA(), a mapping-table will be
  521.   calculated for the whole RGB space. the palette's resolution
  522.   is a significant factor then: a 12bit RGB space holds 4096
  523.   colors, a 15bit RGB space has got 32768 colors, and a 18bit
  524.   RGB space contains 262144 colors. you better know what you're
  525.   doing when creating a mapping-engine for a 18bit palette and
  526.   do not specify a histogram.
  527.  
  528.   * ¹note: nothing serious happens if the supplied histogram
  529.   does not correctly represent the data you convert with a
  530.   mapping-engine. however, colors that are not part of the
  531.   histogram would be mapped to nonsense pixels. unfortunately
  532.   this applies to conversions with dithering. you should
  533.   disable dithering when histogram-related mapping-engines are
  534.   passed to RenderA() or ConvertChunkyA().
  535.